/**
 * 
 */
package dms.repository.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;

import dms.model.Building;
import dms.model.Dormitory;
import dms.model.form.Repair;
import dms.model.util.FindUtil;
import dms.model.util.PageIterator;
import dms.repository.RepairRepository;
import dms.util.HibernateUtil;

/**
 * @author 李健
 *
 */
public class RepairRepositoryHibernate implements RepairRepository {

	private static final Log log = LogFactory.getLog(RepairRepositoryHibernate.class);
//	private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	
	/* (non-Javadoc)
	 * @see dms.repository.RepairRepository#createRepair(dms.model.form.Repair)
	 */
	@Override
	public Repair createRepair(Repair repair) throws Exception {
		Session session = null;
		Transaction tx = null;
		
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			session.save(repair);
			
		} catch (Exception e) {
			log.error(e.toString());			
			throw e;			
		} 
		return repair;
	}

	/* (non-Javadoc)
	 * @see dms.repository.RepairRepository#deleteRepairById(java.lang.Long)
	 */
	@Override
	public void deleteRepairById(Long id) throws Exception {
		Session session = null;
		Transaction tx = null;
		Repair repair = null;
		
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			repair = (Repair) session.load(Repair.class, id);
			session.delete(repair);
		} catch (Exception e) {
			log.error(e.toString());			
			throw e;			
		} 
	}

	/**
	 * 私有方法，供内部调用
	 * @param start
	 * @param count
	 * @param fromDate
	 * @param toDate
	 * @param building
	 * @param processed
	 * @param applied
	 * @return
	 */
	private PageIterator<Repair> find(int start, int count, Date fromDate, Date toDate, 
			Map keyValue, Boolean processed, Boolean applied) {
		Session session = null;
		Transaction tx = null;
		List<Repair> list = null;
		PageIterator<Repair> iter = null;
		Long allCount = null;		
		
		Object[] queriesAndParams = this.makeQueryAndParams(start, count, fromDate, toDate, keyValue, processed, applied);
		String countQuery = (String) queriesAndParams[0];
		String findQuery = (String) queriesAndParams[1];
		Collection params = (Collection) queriesAndParams[2];
		
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			allCount = FindUtil.calculateAllCount(session, countQuery, params);
			list = FindUtil.getEntitiesByPage(session, findQuery, params, start, count);
			iter = new PageIterator<Repair>(list, allCount, start, count);
	
		} catch (Exception e) {
			log.error(e.toString());			
		}
		return iter;
	}

	/* (non-Javadoc)
	 * @see dms.repository.RepairRepository#findByDormitory(int, int, java.util.Date, java.util.Date, dms.model.Dormitory)
	 */
	@Override
	public PageIterator<Repair> findByDormitory(int start, int count,
			Date fromDate, Date toDate, Dormitory dormitory, Boolean processed, Boolean applied) {
		Map keyValue = new HashMap();
		keyValue.put("dormitory", dormitory);
		return find(start, count, fromDate, toDate, keyValue, processed, applied);
	}

	/* (non-Javadoc)
	 * @see dms.repository.RepairRepository#findById(java.lang.Long)
	 */
	@Override
	public Repair findById(Long id) {
		Session session = null;
		Transaction tx = null;
		Repair repair = null;
		
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			repair = (Repair) session.load(Repair.class, id);
			//initialize property
			Hibernate.initialize(repair);					
		} catch (Exception e) {
			log.error(e.toString());
		} 
		return repair;
	}

	/* (non-Javadoc)
	 * @see dms.repository.RepairRepository#updateRepair(dms.model.form.Repair)
	 */
	@Override
	public Repair updateRepair(Repair repair) throws Exception{
		Session session = null;
		Transaction tx = null;
		Repair r = null;
		
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			r = (Repair) session.merge(repair);
		
		} catch (Exception e) {
			log.error(e.toString());
			throw e;		
		} 
		return r;
	}

	@Override
	public PageIterator<Repair> findByBuilding(int start, int count,
			Date fromDate, Date toDate, Building building, Boolean processed,
			Boolean applied) {
		Map keyValue = new HashMap();
		keyValue.put("building", building);
		return find(start, count, fromDate, toDate, keyValue, processed, applied);
	}

	@Override
	public void deleteRepairs(List<Long> ids) throws Exception {
		Session session = null;
		Transaction tx = null;
		Repair repair = null;
		String deleteQuery = "delete from Repair r where r.id in (:ids) ";
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			session.createQuery(deleteQuery)
				   .setParameterList("ids", ids)
				   .executeUpdate();
			
		} catch (Exception e) {
			log.error(e.toString());	
			throw e;			
		}
	}
	
	private Object[] makeQueryAndParams(int start, int count, Date fromDate, Date toDate, 
			Map keyValue, Boolean processed, Boolean applied) {
	
		String countQuery = "select count(*) from Repair r  ";
		String findQuery = "select r from Repair r  ";
		StringBuffer conditionQuery = new StringBuffer();
		
		if (processed != null || applied != null) {
			conditionQuery.append(" where ");
		}
		
		Collection params = new ArrayList();
				
		if (keyValue != null) {
			if (conditionQuery.indexOf("where") == -1) {
				conditionQuery.append(" where ");
			}
			
			Set set = keyValue.entrySet();
			Iterator keyIter = set.iterator();
			
			while (keyIter.hasNext()) {
				Map.Entry<String, Object> entry = (Entry<String, Object>) keyIter
						.next();
				String name = entry.getKey();
				Object value = entry.getValue();

				conditionQuery.append(" r." + name + " = ? and ");
				params.add(value);
			}
		}
		if (fromDate != null && toDate == null) {
			conditionQuery.append("  r.requestDate >= ?  and ");
			params.add(fromDate);
		}
		if (fromDate == null && toDate != null) {
			conditionQuery.append("  r.requestDate <= ?  and ");
			params.add(toDate);
		}
		if (fromDate != null && toDate != null) {
			conditionQuery.append("  (r.requestDate between ? and ?)  and ");
			params.add(fromDate);
			params.add(toDate);
		}

		if (processed != null && applied != null) {
			if (processed == false) {
				conditionQuery.append(" r.status.processed = false and r.status.applied = false and ");
			}
			if (processed == true && applied == false) {
				conditionQuery.append(" r.status.processed = true and r.status.applied = false and ");
			}
			if (applied == true) {
				conditionQuery.append(" r.status.applied = true and r.status.processed = true and ");
			}
		} else if (processed != null && applied == null) {
			if (processed == true) {
				conditionQuery.append(" r.status.processed = true and r.status.applied = false and ");
			} else {
				conditionQuery.append(" r.status.processed = false and r.status.applied = false and ");
			}
		} else if (applied != null) {
			if (applied == true) {
				conditionQuery.append(" r.status.applied = true  and r.status.processed = true and ");
			} else {
				conditionQuery.append(" r.status.applied = false  and ");
			}
		}
		//最后一种情况都为null，全部
		conditionQuery.append(" r.id = r.id ");
		countQuery += conditionQuery;
		findQuery += conditionQuery;
		
		return new Object[]{countQuery, findQuery, params};
	}

	@Override
	public PageIterator<Repair> findByStatus(int start, int count,
			Date fromDate, Date toDate, Boolean processed, Boolean applied) {
		return this.find(start, count, fromDate, toDate, null, processed, applied);
	}

}
